package com.bestcem.xm.user.service.impl;

import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.enums.AuthErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ReqErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ResourceErrorCodeEnum;
import com.bestcem.xm.user.entity.pojo.UserDO;
import com.bestcem.xm.user.enums.OrganizationStatusEnum;
import com.bestcem.xm.user.enums.UserEnum;
import com.bestcem.xm.user.grpc.client.BpDingTalkGrpcClientService;
import com.bestcem.xm.user.grpc.client.PackageGrpcService;
import com.bestcem.xm.user.grpc.client.dto.DingSessionDataDTO;
import com.bestcem.xm.user.grpc.client.dto.PackageDTO;
import com.bestcem.xm.user.service.*;
import com.bestcem.xm.user.service.dto.user.*;
import com.bestcem.xm.user.service.third.GrowingIOService;
import com.bestcem.xm.user.util.business.UserJwtTokenUtil;
import com.bestcem.xm.user.util.convert.UserConvert;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * 钉钉相关实现类
 *
 * @author panyun <yun.pan@idiaoyan.com>
 * @version v1.0
 * @date 2022/3/31 14:48
 */
@Slf4j
@Service
public class DingTalkServiceImpl implements DingTalkService {

    @Resource
    private UserService userService;

    @Resource
    private OrganizationService organizationService;

    @Resource
    private UserUserRoleService userUserRoleService;

    @Resource
    private RoleService roleService;

    @Resource
    private UserJwtTokenUtil userJwtTokenUtil;

    @Resource
    private SsoService ssoService;

    @Resource
    private PackageGrpcService packageGrpcService;

    @Resource
    private GrowingIOService growingIOService;

    @Resource
    private UserAuthService userAuthService;

    @Resource
    private UserConvert userConvert;

    @Resource
    private BpDingTalkGrpcClientService bpDingTalkGrpcClientService;

    @Override
    public ServiceResult<OrgInfoResultDTO> getOrgInfo(String userName, String password) {
        ServiceResult<List<UserDTO>> userByAuth = userAuthService.findUserByAuth(userName, password, null);
        if (!userByAuth.isSuccess() || CollectionUtils.isEmpty(userByAuth.getData())) {
            return ServiceResult.fail(AuthErrorCodeEnum.USER_NOT_EXISTS, "用户名不存在");
        }

        if (userByAuth.getData().size() == 1) {
            UserDTO user = userByAuth.getData().get(0);
            OrgInfoDTO orgInfoDto = getUserOrgInfo(userConvert.dto2Do(user));
            OrgInfoResultDTO resultDTO = new OrgInfoResultDTO();
            resultDTO.setMultiOrg(Boolean.FALSE)
                    .setOrgCodeList(Collections.singletonList(orgInfoDto));
            return ServiceResult.success(resultDTO);
        } else {
            ArrayList<OrgInfoDTO> orgInfoDtoList = new ArrayList<>();

            List<UserDTO> userList = userByAuth.getData();
            for (UserDTO userDTO : userList) {
                OrgInfoDTO userOrgInfo = getUserOrgInfo(userConvert.dto2Do(userDTO));
                orgInfoDtoList.add(userOrgInfo);
            }
            OrgInfoResultDTO resultDTO = new OrgInfoResultDTO();
            resultDTO.setMultiOrg(Boolean.TRUE)
                    .setOrgCodeList(orgInfoDtoList);
            return ServiceResult.success(resultDTO);
        }
    }

    /**
     * 组装OrgInfoDTO
     *
     * @param userDO
     * @return com.bestcem.xm.user.service.dto.user.OrgInfoDTO
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/31 18:21
     */
    private OrgInfoDTO getUserOrgInfo(UserDO userDO) {
        ServiceResult<OrganizationDTO> organizationDTOServiceResult = organizationService.selectByPrimaryKey(userDO.getOrgId());
        if (!organizationDTOServiceResult.isSuccess() || Objects.isNull(organizationDTOServiceResult.getData())) {
            return new OrgInfoDTO();
        }
        OrganizationDTO organizationDTO = organizationDTOServiceResult.getData();
        OrgInfoDTO orgInfoDTO = new OrgInfoDTO();
        orgInfoDTO.setOrgCode(organizationDTO.getCode())
                .setOrgName(organizationDTO.getName())
                .setOrgId(organizationDTO.getOrgId())
                .setDisplayName(userDO.getName())
                .setUserName(userDO.getUserName());
        return orgInfoDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult<UserGetTokenResultDTO> authToken(String sessionId, String orgCode) {
        // 调用grpc接口获取缓存信息
        DingSessionDataDTO userInfo = bpDingTalkGrpcClientService.getDingSessionData(sessionId);
        if (Objects.isNull(userInfo)) {
            return ServiceResult.fail(AuthErrorCodeEnum.DING_TALK_SESSION_NOT_FOUND, String.format("sessionId:%s不存在", sessionId));
        }

        ServiceResult<OrganizationDTO> organizationServiceResult = organizationService.selectByOrgCode(orgCode);
        if (!organizationServiceResult.isSuccess() || Objects.isNull(organizationServiceResult.getData())) {
            return ServiceResult.fail(ResourceErrorCodeEnum.NOT_FOUND, String.format("orgCode:%s找不到", orgCode));
        }

        UserDTO userDTO = new UserDTO();
        userDTO.setDingUserid(userInfo.getDingUserId())
                .setOrgId(organizationServiceResult.getData().getOrgId());
        ServiceResult<List<UserDTO>> userServiceResult = userService.selectList(userDTO);
        if (!userServiceResult.isSuccess() || CollectionUtils.isEmpty(userServiceResult.getData())) {
            return ServiceResult.fail(AuthErrorCodeEnum.DING_TALK_USER_NOT_FOUND, "未找到已绑定的钉钉用户");
        }
        UserDTO dto = userServiceResult.getData().get(0);
        return getTokenByUser(dto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult<UserGetTokenResultDTO> getTokenByUser(UserDTO dto) {
        AuthDTO jwtData = new AuthDTO();

        OrganizationDTO organizationDTO = new OrganizationDTO();
        organizationDTO.setOrgId(dto.getOrgId());
        organizationDTO.setStatus(OrganizationStatusEnum.ACTIVATED.getStatus());
        ServiceResult<List<OrganizationDTO>> organizationResult = organizationService.selectBySelective(organizationDTO);

        List<OrganizationDTO> organizationDTOList = organizationResult.getData();
        if (!organizationResult.isSuccess() || CollectionUtils.isEmpty(organizationDTOList) || Objects.isNull(organizationDTOList.get(0))) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "org找不到");
        }

        OrganizationDTO organization = organizationDTOList.get(0);
        if (Objects.nonNull(organization.getPackageExpireTime())) {
            Date expire = organization.getPackageExpireTime();
            Date now = new Date();
            if (now.getTime() > expire.getTime()) {
                return ServiceResult.fail(AuthErrorCodeEnum.ORG_EXPIRE, expire.toString());
            }
            jwtData.setPackageExpireTime(expire.toString());
        }
        jwtData.setOrgCode(organization.getCode());
        jwtData.setOrgId(organization.getOrgId());
        jwtData.setUserId(dto.getUserId());
        jwtData.setRealName(dto.getName());
        jwtData.setAvatar(dto.getAvatar());

        ServiceResult<String> adminRole = roleService.getAdminRole(jwtData.getOrgId());
        String adminRoleId = adminRole.getData();
        if (!adminRole.isSuccess() || Objects.isNull(adminRoleId)) {
            return ServiceResult.fail(adminRole.getMsg());
        }
        ServiceResult<List<String>> userIdsByAdminRoleId = userUserRoleService.listUserIdsByRoleId(adminRoleId);
        if (userIdsByAdminRoleId.isSuccess() && !CollectionUtils.isEmpty(userIdsByAdminRoleId.getData())) {
            jwtData.setSuperRole(UserEnum.USER_YES.getFlag());
        } else {
            ServiceResult<String> seniorAdminRole = roleService.getSeniorAdminRole(dto.getUserId());
            String superRoleId = seniorAdminRole.getData();
            if (!seniorAdminRole.isSuccess() || Objects.isNull(superRoleId)) {
                return ServiceResult.fail(seniorAdminRole.getMsg());
            }
            ServiceResult<List<String>> userIdsBySuperRoleId = userUserRoleService.listUserIdsByRoleId(superRoleId);
            if (userIdsBySuperRoleId.isSuccess() && !CollectionUtils.isEmpty(userIdsBySuperRoleId.getData())) {
                jwtData.setSenior(UserEnum.USER_YES.getFlag());
            }
        }

        // 生成jwt
        AuthDTO authDTO = ssoService.buildAuthDTO(dto, organization);
        String token = userJwtTokenUtil.generateToken(authDTO);
        String refreshToken = userJwtTokenUtil.generateRefreshToken(organization.getCode(), dto.getUserId());

        //微信小程序注册时，仅有一个用户也需要显示公司信息
        String userName = getUserName(dto);
        OrgInfoDTO orgInfoDTO = new OrgInfoDTO();
        orgInfoDTO.setOrgCode(organization.getCode())
                .setOrgName(organization.getName())
                .setOrgId(organization.getOrgId())
                .setDisplayName(userName)
                .setUserName(dto.getName());

        // 更新最后登录时间
        ssoService.updateLastLoginTime(dto.getUserId(), dto.getOrgId());

        // 获取埋点数据
        PackageDTO packageDTO = packageGrpcService.getById(organization.getPackageId());
        if (Objects.isNull(packageDTO)) {
            return ServiceResult.fail("获取公司套餐失败");
        }
        GrowingioDTO growingioDTO = growingIOService.getUserProperty(dto, organization, packageDTO.getName());

        UserGetTokenResultDTO resultDTO = new UserGetTokenResultDTO();
        resultDTO.setOrgCode(organization.getCode())
                .setToken(token)
                .setRefreshToken(refreshToken)
                .setOrgInfoDTOList(Collections.singletonList(orgInfoDTO))
                .setGrowingioDTO(growingioDTO);
        return ServiceResult.success(resultDTO);
    }

    private String getUserName(UserDTO dto) {
        String userName;
        if (StringUtils.isNotBlank(dto.getWxUnionid())) {
            userName = "微信昵称:" + dto.getUserName();
        } else if (StringUtils.isNotBlank(dto.getPhone())) {
            userName = "手机:" + dto.getPhone();
        } else {
            userName = dto.getUserName();
        }
        return userName;
    }
}
